﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using GoldenTuney.Zone;
using GoldenTuney.RideMetrics;

namespace GoldenTuney
{
   public abstract  class RideMetric
    {
         public enum MetricType  { Total, Average, Peak } ;
         

        bool    aggregate_;
        double  value_,
                count_, // used when averaging
                conversion_,
                precision_;

        string metricUnits_, imperialUnits_;
        string name_, symbol_;
        MetricType type_;

        public RideMetric() {
        // some sensible defaults
        aggregate_ = true;
        conversion_ = 1.0;
        precision_ = 0;
        type_ = MetricType.Total;
        count_ = 1;
        value_ = 0.0;
    }
    //virtual ~RideMetric() {}

    // The string by which we refer to this RideMetric in the code,
    // configuration files, and caches (like stress.cache).  It should
    // not be translated, and it should never be shown to the user.
    public virtual  string symbol()  { return symbol_; }

    // A short string suitable for showing to the user in the ride
    // summaries, configuration dialogs, etc.  It should be translated
    // using QObject::tr().
    public virtual string name() { return name_; }

    // What type of metric is this?
    // Drives the way metrics combined over a day or week in the
    // Long term metrics charts
    public virtual MetricType type() { return type_; }

    // The units in which this RideMetric is expressed.  It should be
    // translated using QObject::tr().
    public virtual string units(bool metric) { return metric ? metricUnits_ : imperialUnits_; }

    // How many digits after the decimal we should show when displaying the
    // value of a RideMetric.
    public virtual double precision() { return precision_; }

    // The actual value of this ride metric, in the units above.
    public virtual double value(bool metric) { return metric ? value_ : (value_ * conversion_); }

    // for averages the count of items included in the average
    public virtual double count() { return count_; }

    // Factor to multiple value to convert from metric to imperial
    public virtual double conversion() { return conversion_; }

    // Compute the ride metric from a file (Hr Zone Version).
    public abstract void compute(RideFile ride,
                          Zones zones, int zoneRange,
                          HrZones hrZones, int hrZoneRange,
                          System.Collections.Generic.Dictionary<String,RideMetric> deps);

    // Fill in the value of the ride metric using the mapping provided.  For
    // example, average speed might be specified by the mapping
    //
    //   { "km" => "18.0", "seconds" => "3600" }
    //
    // As the name suggests, we use this function instead of compute() to
    // override the value of a RideMetric using a value specified elsewhere.
    //void override(const QMap<QString,QString> &map) {
    //    if (map.contains("value")) value_ = map.value("value").toDouble();
    //}

    // Base implementation of aggregate just sums, derived classes
    // can override this for other purposes
    public virtual void aggregateWith(RideMetric other) {
        switch (type_) {
        default:
        case MetricType.Total:
            setValue(value(true) + other.value(true));
            break;
        case MetricType.Peak:
            setValue(value(true) > other.value(true) ? value(true) : other.value(true));
            break;
        case MetricType.Average:
            setValue(((value(true) * count()) + (other.value(true) * other.count()))
                                / (count()+other.count()));
            break;
        }
    }
    public virtual bool canAggregate() { return aggregate_; }

    //virtual RideMetric *clone() const = 0;

    
    //static Dictionary<string,RideMetric> ;
    public abstract void computeMetrics( RideFile ride,  Zones zones,  HrZones hrZones,
                    List<string> metrics);

    // Initialisers for derived classes to setup basic data

    public void setValue(double x) { value_ = x; }
    public void setCount(double x) { count_ = x; }
    public void setConversion(double x) { conversion_ = x; }
    public void setPrecision(int x) { precision_ = x; }
    public void setMetricUnits(string x) { metricUnits_ = x; }
    public void setImperialUnits(string x) { imperialUnits_ = x; }
    public void setName(string x) { name_ = x; }
    public void setSymbol(string x) { symbol_ = x; }
    public void setType(MetricType x) { type_ = x; }
    public void setAggregate(bool x) { aggregate_ = x; }

   
       
    }
}
